package com.yricky.astral.structure

import com.yricky.astral.project.Hazuki
import com.yricky.astral.signal.*
import com.yricky.astral.structure.scope.ModuleScope

abstract class AstralModule:
    ModuleScope
{

    protected lateinit var mutableNetList: MutableNetList
    protected abstract fun logic()
    protected val _attachments:MutableList<()->String> = ArrayList()
    val attachments:List<()->String> get() = _attachments
    //Implement Checkable
    private var hazukiStandard:Hazuki.HazukiStandard = Hazuki.DefaultStandard
    fun setStandard(standard: Hazuki.HazukiStandard){ hazukiStandard = standard }
    override val standard: Hazuki.HazukiStandard get() =  hazukiStandard

    override fun genNetList(): INetList {
        mutableNetList= object: MutableNetList(getModuleName()){
            override val standard: Hazuki.HazukiStandard = hazukiStandard
        }
        synchronized(mutableNetList){
            logic()
        }
        return mutableNetList
    }

    /**
     * add an input wire signal to this module.
     */
    override fun inputWire(name:String,width:Int): Wire =
        wire(name, width,listOf(Signal.TAG_INPUT)).also { mutableNetList.addI(it) }

    /**
     * add an output wire signal to this module.
     */
    override fun outputWire(name:String,width:Int): Wire =
        wire(name, width, listOf(Signal.TAG_OUTPUT)).also { mutableNetList.addO(it) }

    /**
     * add an output register signal to this module.
     */
    override fun outputReg(name:String,width:Int,timing: ClkRstPair?): Reg =
        reg(name, width, timing).also { mutableNetList.addO(it) }


    /**
     * add a register signal to this module.
     * @see outputReg
     */
    override fun reg(name:String,width:Int,timing: ClkRstPair?): Reg {
        mutableNetList.apply {
            checkNameValidity(name)
            val tmp = Reg(name,width,this,timing)
            netNodes[name] = tmp
            return tmp
        }
    }

    /**
     * add a wire signal to this module.
     * @see inputWire
     * @see outputWire
     */
    override fun wire(name:String,width:Int,tags:Collection<String>?): Wire {
        mutableNetList.apply {
            checkNameValidity(name)
            val tmp = Wire(name,width,tags,this)
            netNodes[name] = tmp
            return tmp
        }
    }
}